home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 22 / AACD 22.iso / AACD / Online / Apache / lib / php / DB / common.php next >
Encoding:
PHP Script  |  2001-03-06  |  16.1 KB  |  616 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stig Bakken <ssb@fast.no>                                   |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // Base class for DB implementations.
  21. //
  22.  
  23. /**
  24.  * DB_common is a base class for DB implementations, and should be
  25.  * inherited by all such.
  26.  */
  27. class DB_common {
  28.     // {{{ properties
  29.  
  30.     var $features;        // assoc of capabilities for this DB implementation
  31.     var $errorcode_map;    // assoc mapping native error codes to DB ones
  32.     var $type;            // DB type (mysql, oci8, odbc etc.)
  33.     var $prepare_tokens;
  34.     var $prepare_types;
  35.     var $prepare_maxstmt;
  36.     var $error_mode = PEAR_ERROR_RETURN;
  37.     var $error_level = E_USER_NOTICE;
  38.     var $error_callback;
  39.     var $last_query = '';
  40.     var $fetchmode = DB_FETCHMODE_DEFAULT;
  41.  
  42.     // }}}
  43.     // {{{ toString()
  44.  
  45.     function toString() {
  46.         $info = get_class($this);
  47.         $info .=
  48.             ": (phptype=" . $this->phptype .
  49.             ", dbsyntax=" . $this->dbsyntax .
  50.             ")";
  51.         if ($this->connection) {
  52.             $info .= " [connected]";
  53.         }
  54.         return $info;
  55.     }
  56.  
  57.     // }}}
  58.     // {{{ constructor
  59.  
  60.     function DB_common() {
  61.         $this->features = array();
  62.         $this->errorcode_map = array();
  63.         $this->fetchmode = DB_FETCHMODE_ORDERED;
  64.     }
  65.  
  66.     // }}}
  67.     // {{{ quoteString()
  68.  
  69.     /**
  70.      * Quotes a string so it can be safely used within string delimiters
  71.      * in a query.
  72.      *
  73.      * @param $string the input string to quote
  74.      *
  75.      * @return string the quoted string
  76.      */
  77.     function quoteString($string) {
  78.         return str_replace("'", "\'", $string);
  79.     }
  80.  
  81.     // }}}
  82.     // {{{ provides()
  83.  
  84.     /**
  85.      * Tell whether a DB implementation or its backend extension
  86.      * supports a given feature.
  87.      *
  88.      * @param $feature name of the feature (see the DB class doc)
  89.      *
  90.      * @return bool whether this DB implementation supports $feature
  91.      */
  92.     function provides($feature) {
  93.         return $this->features[$feature];
  94.     }
  95.  
  96.     // }}}
  97.     // {{{ errorCode()
  98.  
  99.     /**
  100.      * Map native error codes to DB's portable ones.  Requires that
  101.      * the DB implementation's constructor fills in the $errorcode_map
  102.      * property.
  103.      *
  104.      * @param $nativecode the native error code, as returned by the backend
  105.      * database extension (string or integer)
  106.      *
  107.      * @return int a portable DB error code, or FALSE if this DB
  108.      * implementation has no mapping for the given error code.
  109.      */
  110.     function errorCode($nativecode) {
  111.         if ($this->errorcode_map[$nativecode]) {
  112.             return $this->errorcode_map[$nativecode];
  113.         }
  114.         //php_error(E_WARNING, get_class($this)."::errorCode: no mapping for $nativecode");
  115.         // Fall back to DB_ERROR if there was no mapping.  Ideally,
  116.         // this should never happen.
  117.         return $this->raiseError(DB_ERROR, false, false, false, $nativecode);
  118.     }
  119.  
  120.     // }}}
  121.     // {{{ errorMessage()
  122.  
  123.     /**
  124.      * Map a DB error code to a textual message.  This is actually
  125.      * just a wrapper for DB::errorMessage().
  126.      *
  127.      * @param $dbcode the DB error code
  128.      *
  129.      * @return string the corresponding error message, of FALSE
  130.      * if the error code was unknown
  131.      */
  132.     function errorMessage($dbcode) {
  133.         return DB::errorMessage($this->errorcode_map[$dbcode]);
  134.     }
  135.  
  136.     // }}}
  137.     // {{{ raiseError()
  138.  
  139.     /**
  140.      * This method is called by DB to generate an error.
  141.      *
  142.      */
  143.     function &raiseError($code = DB_ERROR, $mode = false, $level = false,
  144.                          $debuginfo = false, $nativecode = false) {
  145.         if (!$mode) {
  146.             $mode = $this->error_mode;
  147.         }
  148.         if ($mode == PEAR_ERROR_CALLBACK) {
  149.             if (!is_string($level) &&
  150.                 !(is_array($level) && sizeof($level) == 2 &&
  151.                   is_object($level[0]) && is_string($level[1]))) {
  152.                 $level = $this->error_callback;
  153.             }
  154.         } else {
  155.             if (!$level) {
  156.                 $level = $this->error_level;
  157.             }
  158.         }
  159.         if (!$debuginfo) {
  160.             $debuginfo = $this->last_query;
  161.         }
  162.         if ($nativecode) {
  163.             $debuginfo .= " [nativecode=$nativecode]";
  164.         }
  165.         return new DB_Error($code, $mode, $level, $debuginfo);
  166.     }
  167.  
  168.     // }}}
  169.     // {{{ setErrorHandling()
  170.  
  171.     /**
  172.      * Sets how errors generated by this DB object should be handled.
  173.      *
  174.      * @param $mode int
  175.      *        one of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  176.      *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE or
  177.      *        PEAR_ERROR_CALLBACK.
  178.      *
  179.      * @param $options mixed
  180.      *        Ignored unless $mode is PEAR_ERROR_TRIGGER or
  181.      *        PEAR_ERROR_CALLBACK.  When $mode is PEAR_ERROR_TRIGGER,
  182.      *        this parameter is expected to be an integer among
  183.      *        E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR.  When
  184.      *        $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  185.      *        to be the callback function or method.  A callback
  186.      *        function is a string with the name of the function, a
  187.      *        callback method is an array of two elements: the element
  188.      *        at index 0 is an object, and the element at index 1 is
  189.      *        the name of the method to call in the object.
  190.      *
  191.      * @see PEAR_ERROR_RETURN
  192.      * @see PEAR_ERROR_PRINT
  193.      * @see PEAR_ERROR_TRIGGER
  194.      * @see PEAR_ERROR_DIE
  195.      * @see PEAR_ERROR_CALLBACK
  196.      */
  197.     function setErrorHandling($mode, $options = false) {
  198.         switch ($mode) {
  199.             case PEAR_ERROR_RETURN:
  200.             case PEAR_ERROR_PRINT:
  201.             case PEAR_ERROR_TRIGGER:
  202.             case PEAR_ERROR_DIE:
  203.                 $this->error_mode = $mode;
  204.                 if (!$options) {
  205.                     $this->error_level = E_USER_NOTICE;
  206.                 } else {
  207.                     $this->error_level = $options;
  208.                 }
  209.                 break;
  210.             case PEAR_ERROR_CALLBACK:
  211.                 $this->error_mode = $mode;
  212.                 if (is_string($options) ||
  213.                     (is_array($options) && sizeof($options) == 2 &&
  214.                      is_object($options[0]) && is_string($options[1]))) {
  215.                     $this->error_callback = $options;
  216.                 } else {
  217.                     trigger_error(E_USER_WARNING, "invalid error callback");
  218.                 }
  219.                 $this->error_level = PEAR_ERROR_RETURN;
  220.                 break;
  221.             default:
  222.                 trigger_error(E_USER_WARNING, "invalid error mode");
  223.                 break;
  224.         }
  225.     }
  226.  
  227.     // }}}
  228.     // {{{ setFetchMode()
  229.  
  230.     /**
  231.      * Sets which fetch mode should be used by default on queries
  232.      * on this connection.
  233.      *
  234.      * @param $fetchmode int DB_FETCHMODE_ORDERED or
  235.      *        DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with
  236.      *        DB_FETCHMODE_FLIPPED.
  237.      *
  238.      * @see DB_FETCHMODE_ORDERED
  239.      * @see DB_FETCHMODE_ASSOC
  240.      * @see DB_FETCHMODE_FLIPPED
  241.      */
  242.     function setFetchMode($fetchmode) {
  243.         switch ($fetchmode) {
  244.             case DB_FETCHMODE_ORDERED:
  245.             case DB_FETCHMODE_ASSOC:
  246.                 $this->fetchmode = $fetchmode;
  247.                 break;
  248.             default:
  249.                 return $this->raiseError("invalid get mode");
  250.         }
  251.     }
  252.  
  253.     // }}}
  254.     // {{{ prepare()
  255.  
  256.     /**
  257.      * Prepares a query for multiple execution with execute().  With
  258.      * PostgreSQL, this is emulated.
  259.      */
  260.     function prepare($query) {
  261.         $tokens = split('[\&\?]', $query);
  262.         $token = 0;
  263.         $types = array();
  264.         for ($i = 0; $i < strlen($query); $i++) {
  265.             switch ($query[$i]) {
  266.                 case '?':
  267.                     $types[$token++] = DB_PARAM_SCALAR;
  268.                     break;
  269.                 case '&':
  270.                     $types[$token++] = DB_PARAM_OPAQUE;
  271.                     break;
  272.             }
  273.         }
  274.         $this->prepare_tokens[] = &$tokens;
  275.         end($this->prepare_tokens);
  276.         $k = key($this->prepare_tokens);
  277.         $this->prepare_types[$k] = $types;
  278.         return $k;
  279.     }
  280.  
  281.     // }}}
  282.     // {{{ execute_emulate_query()
  283.  
  284.     /**
  285.      * @return a string containing the real query run when emulating
  286.      * prepare/execute.  A DB error code is returned on failure.
  287.      */
  288.     function execute_emulate_query($stmt, $data = false) {
  289.         $p = &$this->prepare_tokens;
  290.         $stmt = (int)$this->prepare_maxstmt++;
  291.         if (!isset($this->prepare_tokens[$stmt]) ||
  292.             !is_array($this->prepare_tokens[$stmt]) ||
  293.             !sizeof($this->prepare_tokens[$stmt])) {
  294.             return $this->raiseError(DB_ERROR_INVALID);
  295.         }
  296.         $qq = &$this->prepare_tokens[$stmt];
  297.         $qp = sizeof($qq) - 1;
  298.         if ((!$data && $qp > 0) ||
  299.             (!is_array($data) && $qp > 1) ||
  300.             (is_array($data) && $qp > sizeof($data))) {
  301.             return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  302.         }
  303.         $realquery = $qq[0];
  304.         for ($i = 0; $i < $qp; $i++) {
  305.             if ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) {
  306.                 if (is_array($data)) {
  307.                     $fp = fopen($data[$i], "r");
  308.                 } else {
  309.                     $fp = fopen($data, "r");
  310.                 }
  311.                 $pdata = '';
  312.                 if ($fp) {
  313.                     while (($buf = fread($fp, 4096)) != false) {
  314.                         $pdata .= $buf;
  315.                     }
  316.                 }
  317.             } else {
  318.                 if (is_array($data)) {
  319.                     $pdata = &$data[$i];
  320.                 } else {
  321.                     $pdata = &$data;
  322.                 }
  323.             }
  324.             $realquery .= "'" . $this->quoteString($pdata) . "'";
  325.             $realquery .= $qq[$i + 1];
  326.         }
  327.         return $realquery;
  328.     }
  329.  
  330.     // }}}
  331.  
  332.     // {{{ executeMultiple()
  333.  
  334.     /**
  335.      * This function does several execute() calls on the same
  336.      * statement handle.  $data must be an array indexed numerically
  337.      * from 0, one execute call is done for every "row" in the array.
  338.      *
  339.      * If an error occurs during execute(), executeMultiple() does not
  340.      * execute the unfinished rows, but rather returns that error.
  341.      */
  342.     function executeMultiple($stmt, &$data) {
  343.         for ($i = 0; $i < sizeof($data); $i++) {
  344.             $res = $this->execute($stmt, $data[$i]);
  345.             if (DB::isError($res)) {
  346.                 return $res;
  347.             }
  348.         }
  349.         return DB_OK;
  350.     }
  351.  
  352.     // }}}
  353.     // {{{ getOne()
  354.  
  355.     /**
  356.      * Fetch the first column of the first row of data returned from
  357.      * a query.  Takes care of doing the query and freeing the results
  358.      * when finished.
  359.      *
  360.      * @param $query the SQL query
  361.      * @param $params if supplied, prepare/execute will be used
  362.      *        with this array as execute parameters
  363.      * @access public
  364.      */
  365.     function &getOne($query, $params = array()) {
  366.         if (sizeof($params) > 0) {
  367.             $sth = $this->prepare($query);
  368.             if (DB::isError($sth)) {
  369.                 return $sth;
  370.             }
  371.             $res = $this->execute($sth, $params);
  372.         } else {
  373.             $res = $this->simpleQuery($query);
  374.         }
  375.         if (DB::isError($res)) {
  376.             return $res;
  377.         }
  378.         $row = $this->fetchRow($res, DB_FETCHMODE_ORDERED);
  379.         if (DB::isError($row)) {
  380.             return $row;
  381.         }
  382.         $ret = &$row[0];
  383.         $this->freeResult($res);
  384.         if (isset($sth)) {
  385.             $this->freeResult($sth);
  386.         }
  387.         return $ret;
  388.     }
  389.  
  390.     // }}}
  391.     // {{{ getRow()
  392.  
  393.     /**
  394.      * Fetch the first row of data returned from a query.  Takes care
  395.      * of doing the query and freeing the results when finished.
  396.      *
  397.      * @param $query the SQL query
  398.      * @access public
  399.      * @return array the first row of results as an array indexed from
  400.      * 0, or a DB error code.
  401.      */
  402.     function &getRow($query, $fetchmode = DB_FETCHMODE_DEFAULT, $params = array()) {
  403.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  404.             $fetchmode = $this->fetchmode;
  405.         }
  406.         if (sizeof($params) > 0) {
  407.             $sth = $this->prepare($query);
  408.             if (DB::isError($sth)) {
  409.                 return $sth;
  410.             }
  411.             $res = $this->execute($sth, $params);
  412.         } else {
  413.             $res = $this->simpleQuery($query);
  414.         }
  415.         if (DB::isError($res)) {
  416.             return $res;
  417.         }
  418.         $row = $this->fetchRow($res, $fetchmode);
  419.         if (DB::isError($row)) {
  420.             return $row;
  421.         }
  422.         $this->freeResult($res);
  423.         if (isset($sth)) {
  424.             $this->freeResult($sth);
  425.         }
  426.         return $row;
  427.     }
  428.  
  429.     // }}}
  430.     // {{{ getCol()
  431.  
  432.     /**
  433.      * Fetch a single column from a result set and return it as an
  434.      * indexed array.
  435.      *
  436.      * @param $query the SQL query
  437.      *
  438.      * @param $col which column to return (integer [column number,
  439.      * starting at 0] or string [column name])
  440.      *
  441.      * @access public
  442.      *
  443.      * @return array an indexed array with the data from the first
  444.      * row at index 0, or a DB error code.
  445.      */
  446.     function &getCol($query, $col = 0, $params = array()) {
  447.         if (sizeof($params) > 0) {
  448.             $sth = $this->prepare($query);
  449.             if (DB::isError($sth)) {
  450.                 return $sth;
  451.             }
  452.             $res = $this->execute($sth, $params);
  453.         } else {
  454.             $res = $this->simpleQuery($query);
  455.         }
  456.         if (DB::isError($res)) {
  457.             return $res;
  458.         }
  459.         $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
  460.         $ret = array();
  461.         while ($row = $this->fetchRow($res, $fetchmode)) {
  462.             if (DB::isError($row)) {
  463.                 $ret = $row;
  464.                 break;
  465.             }
  466.             $ret[] = $row[$col];
  467.         }
  468.         $this->freeResult($res);
  469.         if (isset($sth)) {
  470.             $this->freeResult($sth);
  471.         }
  472.         return $ret;
  473.     }
  474.  
  475.     // }}}
  476.     // {{{ getAssoc()
  477.  
  478.     /**
  479.      * Fetch the entire result set of a query and return it as an
  480.      * associative array using the first column as the key.
  481.      *
  482.      * @param $query the SQL query
  483.      *
  484.      * @param $force_array (optional) used only when the query returns
  485.      * exactly two columns.  If true, the values of the returned array
  486.      * will be one-element arrays instead of scalars.
  487.      *
  488.      * @access public
  489.      *
  490.      * @return array associative array with results from the query.
  491.      * If the result set contains more than two columns, the value
  492.      * will be an array of the values from column 2-n.  If the result
  493.      * set contains only two columns, the returned value will be a
  494.      * scalar with the value of the second column (unless forced to an
  495.      * array with the $force_array parameter).  A DB error code is
  496.      * returned on errors.  If the result set contains fewer than two
  497.      * columns, a DB_ERROR_TRUNCATED error is returned.
  498.      *
  499.      * For example, if the table "mytable" contains:
  500.      *
  501.      *  ID      TEXT       DATE
  502.      * --------------------------------
  503.      *  1       'one'      944679408
  504.      *  2       'two'      944679408
  505.      *  3       'three'    944679408
  506.      *
  507.      * Then the call getAssoc('SELECT id,text FROM mytable') returns:
  508.      *   array(
  509.      *     '1' => 'one',
  510.      *     '2' => 'two',
  511.      *     '3' => 'three',
  512.      *   )
  513.      *
  514.      * ...while the call getAssoc('SELECT id,text,date FROM mydate') returns:
  515.      *   array(
  516.      *     '1' => array('one', '944679408'),
  517.      *     '2' => array('two', '944679408'),
  518.      *     '3' => array('three', '944679408')
  519.      *   )
  520.      *
  521.      * Keep in mind that database functions in PHP usually return string
  522.      * values for results regardless of the database's internal type.
  523.      */
  524.     function &getAssoc($query, $force_array = false, $params = array()) {
  525.         if (sizeof($params) > 0) {
  526.             $sth = $this->prepare($query);
  527.             if (DB::isError($sth)) {
  528.                 return $sth;
  529.             }
  530.             $res = $this->execute($sth, $params);
  531.         } else {
  532.             $res = $this->simpleQuery($query);
  533.         }
  534.         if (DB::isError($res)) {
  535.             return $res;
  536.         }
  537.         $cols = $this->numCols($res);
  538.         if ($cols < 2) {
  539.             return $this->raiseError(DB_ERROR_TRUNCATED);
  540.         }
  541.         $results = array();
  542.         if ($cols > 2 || $force_array) {
  543.             // return array values
  544.             // XXX this part can be optimized
  545.             while (($row = $this->fetchRow($res, DB_FETCHMODE_ORDERED))
  546.                    && !DB::isError($row)) {
  547.                 reset($row);
  548.                 // we copy the row of data into a new array
  549.                 // to get indices running from 0 again
  550.                 $results[$row[0]] = array_slice($row, 1);
  551.             }
  552.         } else {
  553.             // return scalar values
  554.             while (($row = $this->fetchRow($res)) && !DB::isError($row)) {
  555.                 $results[$row[0]] = $row[1];
  556.             }
  557.         }
  558.         $this->freeResult($res);
  559.         if (isset($sth)) {
  560.             $this->freeResult($sth);
  561.         }
  562.         return $results;
  563.     }
  564.  
  565.     // }}}
  566.     // {{{ getAll()
  567.  
  568.     /**
  569.      * Fetch all the rows returned from a query.
  570.      *
  571.      * @param $query the SQL query
  572.      * @access public
  573.      * @return array an nested array, or a DB error
  574.      */
  575.     function &getAll($query, $fetchmode = DB_FETCHMODE_DEFAULT, $params = array()) {
  576.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  577.             $fetchmode = $this->fetchmode;
  578.         }
  579.         if (sizeof($params) > 0) {
  580.             $sth = $this->prepare($query);
  581.             if (DB::isError($sth)) {
  582.                 return $sth;
  583.             }
  584.             $res = $this->execute($sth, $params);
  585.         } else {
  586.             $res = $this->simpleQuery($query);
  587.         }
  588.         if (DB::isError($res)) {
  589.             return $res;
  590.         }
  591.         $results = array();
  592.         while (($row = $this->fetchRow($res, $fetchmode)) && !DB::isError($row)) {
  593.             if ($fetchmode & DB_FETCHMODE_FLIPPED) {
  594.                 foreach ($row as $key => $val) {
  595.                     $results[$key][] = $val;
  596.                 }
  597.             } else {
  598.                 $results[] = $row;
  599.             }
  600.         }
  601.         $this->freeResult($res);
  602.         if (isset($sth)) {
  603.             $this->freeResult($sth);
  604.         }
  605.         return $results;
  606.     }
  607.  
  608.     // }}}
  609. }
  610.  
  611. // Local variables:
  612. // tab-width: 4
  613. // c-basic-offset: 4
  614. // End:
  615. ?>
  616.